﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Web;
using System.IO;
using System.Configuration;
using System.Web.Configuration;
using Microsoft.SqlServer.Server;

namespace TimeManagementSystem
{
    public class InputValidator
    {
        public DAO dao;

        public InputValidator()
        {
            dao = new DAO();
        }

        public string AuthorizeUser(string login, string password, string standardSessionId)
        {
            var chipher = new RC4(ConfigurationManager.AppSettings.Get("mainKey"));
            var user=dao.AuthorizeUser(login, chipher.Encode(password));
            if (user != null)
            {
                var sessionId = GenerateSessionId();
                chipher = new RC4(standardSessionId);
                dao.SetUserSessionId(user, chipher.Encode(sessionId));
                return sessionId;
            }
            return null;
        }

        private string GenerateSessionId()
        {
            const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            var random = new Random();
            var result = new string(
                Enumerable.Repeat(chars, 24)
                          .Select(s => s[random.Next(s.Length)])
                          .ToArray());
            return result;
        }

        public User GetUser(string aspId, string sessionId)
        {
            var chipher = new RC4(aspId);
            return dao.GetUserBySessionId(chipher.Encode(sessionId));
        }

        public string GetFilePath(string directoryPath, string fileName)
        {
            return directoryPath + fileName;
        }

        public string GetFileData(string filePath)
        {
            var sr = new StreamReader(filePath);
            string line, result = "";
            while ((line = sr.ReadLine()) != null)
            {
                result += line;
            }
            sr.Close();
            return result;
        }

        public string CreateDescriptionName(string type, int firstId, string name)
        {
            //var newName = name.Replace(' ', '`');
            return type + "~" + firstId + "~" + name + ".txt";
        }

        public void SaveDescriptionsToFile(string description, string filePath)
        {
            if (!File.Exists(filePath))
            {
                File.Create(filePath).Close();
            }
            var sw = new StreamWriter(filePath);
            try
            {
                sw.Write(description);
            }
            catch (Exception)
            {
                throw new Exception("Can't save description in the file!!!");
            }
            finally
            {
                sw.Close();
            }
        }

        private void RemoveDescription(string path)
        {
            if (File.Exists(path))
                File.Delete(path);
        }

        public void AddGoal(string goalName, string creatorLogin)
        {
            var user = dao.SearchUser(creatorLogin);
            Goal goal = null;
            if (user != null)
                goal = dao.SearchGoal(goalName, user.Id);
            if (goal == null)
            {
                if (user != null)
                {
                    if (user.Status == "Admin" || user.Status == "Manager")
                    {
                        try
                        {
                            dao.AddGoal(goalName, user.Id);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Can't add new goal!!!");
                        }
                    }
                    else throw new Exception("You have no access to create goals!!!");
                }
                else throw new Exception("There is no such user '" + creatorLogin + "' in the system!!!");
            }
            else throw new Exception("Such goal already exists in your list!!!");
        }

        public void RemoveGoal(string goalName, string login, string goalOwner)
        {
            var user = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (user != null)
                goal = dao.SearchGoal(goalName, user.Id);
            if (goal != null)
            {
                var whoRemove = dao.SearchUser(goalOwner);
                if (whoRemove != null)
                {
                    if (whoRemove.Status == "Admin" || whoRemove.Status == "Manager" && goal.CreatedBy == whoRemove.Id)
                    {
                        try
                        {
                            var tasks = dao.GetAllTasksInGoal(goal.Id);
                            for (var i = 0; i < tasks.Count; i++)
                            {
                                RemoveTask(goalName, tasks[i].Name, login, goalOwner);
                            }
                            dao.RemoveGoal(goal);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Cant remove goal!!!");
                        }
                    }
                    else throw new Exception("You have no access to remove goals!!!");
                }
                else throw new Exception("There is no such user '" + login + "' in the system!!!");
            }
            else throw new Exception("There is no such goal you want to remove!!!");
        }

        public void RenameGoal(string oldGoalName, string newGoalName, string login)
        {
            var user = dao.SearchUser(login);
            Goal goal = null;
            if (user != null)
                goal = dao.SearchGoal(oldGoalName, user.Id);
            if (goal != null)
            {
                try
                {
                    dao.RenameGoal(goal, newGoalName);
                }
                catch (Exception ex)
                {
                    throw new Exception("Can't change name of goal '" + oldGoalName + "'!!!");
                }
            }
            else
            {
                throw new Exception("There is no such goal you want to rename!!!");
            }
        }

        public void AddUser(string name, string surname, string patronymic, string email, string login, string password, string status, string creatorLogin)
        {
            var user = dao.SearchUser(login);
            if (user == null)
            {
                var creator = dao.SearchUser(creatorLogin);
                if (creator != null)
                {
                    if (creator.Status == "Admin" || creator.Status == "Manager")
                    {
                        try
                        {
                            var chipher = new RC4(ConfigurationManager.AppSettings.Get("mainKey"));
                            dao.AddUser(name, surname, patronymic, email, login, chipher.Encode(password), status);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Can't create new user!!!");
                        }
                    }
                    else throw new Exception("You have no access to register new users!!!");
                }
                else throw new Exception("There is no such user '" + creatorLogin + "' in the system!!!");
            }
            else throw new Exception("User with such login already exists!!!");
        }

        public void RemoveUser(int id, string creatorLogin)
        {
            var user = dao.GetUserById(id);
            if (user != null)
            {
                var creator = dao.SearchUser(creatorLogin);
                if (creator != null)
                {
                    if (creator.Status == "Admin" || creator.Status == "Manager")
                    {
                        try
                        {
                            dao.RemoveUser(user);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Can't remove user!!!");
                        }
                    }
                    else throw new Exception("You have no access to remove users!!!");
                }
                else throw new Exception("There is no such user '" + creatorLogin + "' in the system!!!");
            }
            else throw new Exception("There is no such user in the system you want to remove!!!");
        }

        public void ChangeUserStatus(string login, string newStatus, string creatorLogin)
        {
            var user = dao.SearchUser(login);
            if (user != null)
            {
                var creator = dao.SearchUser(creatorLogin);
                if (creator != null)
                {
                    if (creator.Status == "Admin" || creator.Status == "Manager")
                    {
                        try
                        {
                            dao.ChangeUserStatus(user, newStatus);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Can't change user status!!!");
                        }
                    }
                    else throw new Exception("You have no access to change user statuses!!!");
                }
                else throw new Exception("There is no such user '" + creatorLogin + "' in the system!!!");
            }
            else throw new Exception("There is no such user '" + login + "' in the system!!!");
        }

        public void EditUser(int id, string name, string sname, string patronymic, string email, string login, string status, string creatorLogin)
        {
            var user = dao.GetUserById(id);
            if (user != null)
            {
                if (dao.SearchUser(login) == null || login == user.Login)
                {
                    var creator = dao.SearchUser(creatorLogin);
                    if (creator != null)
                    {
                        if (creator.Status == "Admin" || creator.Status == "Manager")
                        {
                            try
                            {
                                dao.EditUser(user, name, sname, patronymic, email, login, status);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Can't change user!!!");
                            }
                        }
                        else throw new Exception("You have no access to remove users!!!");
                    }
                    else throw new Exception("There is no such user '" + creatorLogin + "' in the system!!!");
                }
                else throw new Exception("User with such login already exists!!!");
            }
            else throw new Exception("There is no such user in the system you want to remove!!!");
        }

        public void AddTask(string goalName, string taskName, string taskDescription, string status,
            string priority, DateTime startDate, DateTime finishDate, string assignedTo, string login, string creatorLogin)//test work with descriptions
        {
            var action = "";
            var user = dao.SearchUser(creatorLogin);
            Goal goal = null;
            if (user != null)
                goal = dao.SearchGoal(goalName, user.Id);
            if (goal != null)
            {
                var task = dao.SearchTask(goal.Id, taskName);
                try
                {
                    string descriptionName;
                    var assigned = dao.SearchUser(assignedTo);
                    int userId = 0;
                    if (assigned != null)
                        userId = assigned.Id;
                    if (task == null)
                    {
                        action = "add new ";
                        var creator = dao.SearchUser(login);
                        int creatorId = 0;
                        if (creator != null)
                            creatorId = creator.Id;
                        descriptionName = CreateDescriptionName("task", goal.Id, taskName);
                        dao.AddTask(goal.Id, taskName, descriptionName, status, priority,
                            startDate, finishDate, userId, creatorId);
                    }
                    else
                    {
                        action = "change ";
                        descriptionName = task.Description;
                        dao.ChangeTask(task, taskName, status, priority,
                            startDate, finishDate, userId);
                    }
                    SaveDescriptionsToFile(taskDescription,
                        GetFilePath(ConfigurationManager.AppSettings.Get("taskDescriptions"), descriptionName));
                }
                catch (Exception ex)
                {
                    throw new Exception("Can't " + action + "task!!!");
                }
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void RemoveTask(string goalName, string taskName, string login, string goalOwner) //test work with descriptions
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                var task = dao.SearchTask(goal.Id, taskName);
                if (task != null)
                {
                    var user = dao.SearchUser(login);
                    if (user != null)
                    {
                        if (user.Status == "Admin" || (user.Status == "Manager" && goal.CreatedBy == user.Id)
                            || task.CreatedBy == user.Id)
                        {
                            try
                            {
                                RemoveDescription(GetFilePath(ConfigurationManager.AppSettings.Get("taskDescriptions"),
                                    task.Description));
                                var bugs = dao.GetAllCommentsInBug(task.Id);
                                for (var i = 0; i < bugs.Count; i++)
                                {
                                    RemoveBug(goalName, taskName, bugs[i].Name, login, goalOwner);
                                }
                                dao.RemoveTask(task);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Cant remove task!!!");
                            }
                        }
                        else throw new Exception("You have no access to remove task!!!");
                    }
                    else throw new Exception("There is no such user '" + login + "' in the system!!!");
                }
                else throw new Exception("There is no such task you want to remove!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void ChangeTaskPriority(string goalName, string taskName, string priority, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                var task = dao.SearchTask(goal.Id, taskName);
                if (task != null)
                {
                    try
                    {
                        dao.ChangeTaskPriority(task, priority);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Can't change priority for the task!!!");
                    }
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void ChangeTaskStatus(string goalName, string taskName, string status, string login, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                var task = dao.SearchTask(goal.Id, taskName);
                if (task != null)
                {
                    var user = dao.SearchUser(login);
                    if (user != null)
                    {
                        if (user.Status == "Developer" || user.Status == "Tester" && status == "TO DO" ||
                            status == "Done")
                            throw new Exception("You have no rights to set this status!!!");
                        if (user.Status == "Admin" || user.Status == "Manager" || 
                            (user.Status == "Developer" || user.Status == "Tester" && task.CreatedBy == user.Id))
                        {
                            try
                            {
                                dao.ChangeTaskStatus(task, status);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Can't change status of the task!!!");
                            }
                        }
                    }
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void ChangeTaskDescription(string goalName, string taskName, string description, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                var task = dao.SearchTask(goal.Id, taskName);
                if (task != null)
                {
                    var descriptionName = task.Description;
                    SaveDescriptionsToFile(description, GetFilePath
                        (ConfigurationManager.AppSettings.Get("taskDescriptions"), descriptionName));
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void AddBug(string goalName, string taskName, string bugName, string bugDescription, string type,
            string category, string status, string version, string reportedBy, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    var bug = dao.SearchBug(task.Id, bugName);
                    var action = "";
                    try
                    {
                        string descriptionName;
                        var user = dao.SearchUser(reportedBy); //add additional security for user search
                        if (bug == null)
                        {
                            action = "add new ";
                            descriptionName = CreateDescriptionName("bug", task.Id, bugName);
                            dao.AddBug(task, bugName, bugDescription, type, category, version, user.Id);
                        }
                        else
                        {
                            action = "change ";
                            descriptionName = bug.Description;
                            var newStaus = bug.Status;
                            if (user.Status == "Admin" || (user.Status == "Developer" && bug.ReportedBy == user.Id)
                                || (user.Status == "Manager" && goal.CreatedBy == user.Id) || user.Status == "Tester")
                                newStaus = status;
                            dao.ChangeBug(bug, bugName, type, category, version, newStaus, user.Id);
                        }
                        SaveDescriptionsToFile(bugDescription,
                            GetFilePath(ConfigurationManager.AppSettings.Get("bugDescriptions"), descriptionName));
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Can't " + action + "bug!!!");
                    }
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void RemoveBug(string goalName, string taskName, string bugName, string login, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    var bug = dao.SearchBug(task.Id, bugName);
                    if (bug != null)
                    {
                        var user = dao.SearchUser(login);
                        if (user != null)
                        {
                            if (user.Status == "Admin" || (user.Status == "Manager" && goal.CreatedBy == user.Id)
                                || (user.Status == "Tester" || user.Status == "Developer" && bug.ReportedBy == user.Id))
                            {
                                try
                                {
                                    RemoveDescription(
                                        GetFilePath(ConfigurationManager.AppSettings.Get("bugDescriptions"),
                                            bug.Description));
                                    var comments = dao.GetAllCommentsInBug(bug.Id);
                                    for (var i = 0; i < comments.Count; i++)
                                    {
                                        RemoveComment(goalName, taskName, bugName, comments[i].Name, login, goalOwner);
                                    }
                                    dao.RemoveBug(bug);
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception("Cant remove bug!!!");
                                }
                            }
                            else throw new Exception("You have no access to remove bugs!!!");

                        }
                        else throw new Exception("There is no such user '" + login + "' in the system!!!");
                    }
                    else throw new Exception("There is no such bug you want to remove!!!");
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void ChangeBugStatus(string newStatus, string bugName, string login, string goalName, string taskName,
            string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    var bug = dao.SearchBug(task.Id, bugName);
                    if (bug != null)
                    {
                        var user = dao.SearchUser(login);
                        if (user != null)
                        {
                            if (user.Status == "Admin" || (user.Status == "Developer" && bug.ReportedBy == user.Id)
                                || (user.Status == "Manager" && goal.CreatedBy == user.Id) || user.Status == "Tester")
                            {
                                try
                                {
                                    dao.ChangeBugStatus(bug, newStatus, user.Id);
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception("Can't change bug's status!!!");
                                }
                            }
                            else throw new Exception("You have no access to change bug statuses!!!");
                        }
                        else throw new Exception("There is no such user '" + login + "' in the system!!!");
                    }
                    else throw new Exception("There is no such bug '" + bugName + "' in the system!!!");
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void ChangeBugDescription(string goalName, string taskName, string bugName, string bugDescription,
            string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    var bug = dao.SearchBug(task.Id, bugName);
                    if (bug != null)
                    {
                        var description = bug.Description;
                        SaveDescriptionsToFile(bugDescription, GetFilePath
                            (ConfigurationManager.AppSettings.Get("bugDescriptions"), description));
                    }
                    else throw new Exception("There is no such bug '" + bugName + "' in the system!!!");
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void AddComment(string goalName, string taskName, string bugName, string commentName,
            string commentDescription, string createdBy, string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    Bug bug;
                    if ((bug = dao.SearchBug(task.Id, bugName)) != null)
                    {
                        var comment = dao.SearchComment(bug.Id, commentName);
                        var action = "";
                        try
                        {
                            string descriptionName;
                            var user = dao.SearchUser(createdBy);
                            if (comment == null)
                            {
                                action = "add new ";
                                descriptionName = CreateDescriptionName("comment", bug.Id, commentName);
                                dao.AddComment(bug.Id, commentName, commentDescription, user.Id);
                            }
                            else
                            {
                                action = "change ";
                                descriptionName = comment.Description;
                                if (comment.CreatedBy == user.Id || dao.GetUserStatus(createdBy) == "Admin" ||
                                    dao.GetUserStatus(createdBy) == "Manager")
                                    dao.ChangeComment(comment, commentName);
                            }
                            SaveDescriptionsToFile(commentDescription,
                                GetFilePath(ConfigurationManager.AppSettings.Get("commentDescriptions"), descriptionName));
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Can't " + action + "comment!!!");
                        }
                    }
                    else throw new Exception("There is no such bug '" + bugName + "' in the system!!!");
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }

        public void RemoveComment(string goalName, string taskName, string bugName, string commentName, string login,
            string goalOwner)
        {
            var owner = dao.SearchUser(goalOwner);
            Goal goal = null;
            if (owner != null)
                goal = dao.SearchGoal(goalName, owner.Id);
            if (goal != null)
            {
                Task task;
                if ((task = dao.SearchTask(goal.Id, taskName)) != null)
                {
                    Bug bug;
                    if ((bug = dao.SearchBug(task.Id, bugName)) != null)
                    {
                        var comment = dao.SearchComment(bug.Id, commentName);
                        if (comment != null)
                        {
                            var user = dao.SearchUser(login);
                            if (user != null)
                            {
                                if (user.Status == "Admin" || user.Status == "Manager" || comment.CreatedBy == user.Id ||
                                    bug.ReportedBy == user.Id)
                                {
                                    try
                                    {
                                        RemoveDescription(
                                            GetFilePath(ConfigurationManager.AppSettings.Get("commentDescriptions"),
                                                comment.Description));
                                        dao.RemoveComment(comment);
                                    }
                                    catch (Exception)
                                    {
                                        throw new Exception("Cant remove comment!!!");
                                    }
                                }
                                else throw new Exception("You have no access to remove this comment!!!");
                            }
                            else throw new Exception("There is no such user '" + login + "' in the system!!!");
                        }
                        else throw new Exception("There is no such comment you want to remove!!!");
                    }
                    else throw new Exception("There is no such bug '" + bugName + "' in the system!!!");
                }
                else throw new Exception("There is no such task in goal: " + goalName + "!!!");
            }
            else throw new Exception("There is no such goal in the system!!!");
        }
    }
}